import type { ReactElement } from 'react';
import React, { useEffect, useState } from 'react';
import { useMutation, useQuery } from '@tanstack/react-query';
import { FlexCol, FlexRow } from '../utilities';
import {
  Typography,
  TypographyColor,
  TypographyType,
} from '../typography/Typography';
import Textarea from '../fields/Textarea';
import { Radio } from '../fields/Radio';
import { Checkbox } from '../fields/Checkbox';
import { Dropdown } from '../fields/Dropdown';
import { TextField } from '../fields/TextField';
import { useAuthContext } from '../../contexts/AuthContext';
import { getCandidatePreferencesOptions } from '../../features/opportunity/queries';
import { RoleType } from '../../features/opportunity/types';
import { LocationType } from '../../features/opportunity/protobuf/util';
import {
  EmploymentType,
  SalaryPeriod,
} from '../../features/opportunity/protobuf/opportunity';
import type { UpdatedCandidatePreferences } from '../../features/opportunity/mutations';
import {
  candidateAddKeywordMutationOptions,
  candidateRemoveKeywordMutationOptions,
  updateCandidatePreferencesMutationOptions,
} from '../../features/opportunity/mutations';
import { useUpdateQuery } from '../../hooks/useUpdateQuery';
import useDebounceFn from '../../hooks/useDebounceFn';
import { useActions, useToastNotification } from '../../hooks';
import { ActionType } from '../../graphql/actions';
import { stringToBoolean } from '../../lib/utils';
import { KeywordSelection } from '../../features/opportunity/components/KeywordSelection';
import { useLogContext } from '../../contexts/LogContext';
import { LogEvent } from '../../lib/log';

const salaryDurationOptions = [
  { label: 'Annually', value: SalaryPeriod.ANNUAL },
  { label: 'Monthly', value: SalaryPeriod.MONTHLY },
  { label: 'Weekly', value: SalaryPeriod.WEEKLY },
  { label: 'Daily', value: SalaryPeriod.DAILY },
  { label: 'Hourly', value: SalaryPeriod.HOURLY },
];

const salaryOptions = salaryDurationOptions.map((option) => option.label);

const locationTypeOptions = [
  { label: 'Remote', value: LocationType.REMOTE },
  { label: 'Hybrid', value: LocationType.HYBRID },
  { label: 'On-site', value: LocationType.OFFICE },
];

const employmentTypeOptions = [
  { label: 'Full-time', value: EmploymentType.FULL_TIME },
  { label: 'Part-time', value: EmploymentType.PART_TIME },
  { label: 'Contract / Freelance', value: EmploymentType.CONTRACT },
  { label: 'Internship', value: EmploymentType.INTERNSHIP },
];

const DEBOUNCE_DELAY_MS = 750;

export const PreferenceOptionsForm = (): ReactElement => {
  const { logEvent } = useLogContext();
  const [selectedSalaryOption, setSelectedSalaryOption] = useState(0);
  const { displayToast } = useToastNotification();
  const { completeAction } = useActions();
  const { user } = useAuthContext();

  const opts = getCandidatePreferencesOptions(user?.id);
  const { data: preferences } = useQuery(opts);
  const { mutate: updatePreferences } = useMutation({
    ...updateCandidatePreferencesMutationOptions(
      useUpdateQuery(opts),
      (variables) => {
        completeAction(ActionType.UserCandidatePreferencesSaved);

        Object.keys(variables).forEach((prefKey) => {
          logEvent({
            event_name: LogEvent.UpdateCandidatePreferences,
            target_id: prefKey,
          });
        });
      },
    ),
    onError: () => {
      displayToast('Failed to update preferences. Please try again.');
    },
  });

  const { mutate: addKeyword } = useMutation({
    ...candidateAddKeywordMutationOptions(useUpdateQuery(opts)),
    onError: () => {
      displayToast('Failed to add keyword. Please try again.');
    },
  });
  const { mutate: removeKeyword } = useMutation({
    ...candidateRemoveKeywordMutationOptions(useUpdateQuery(opts)),
    onError: () => {
      displayToast('Failed to remove keyword. Please try again.');
    },
  });

  const [debouncedUpdate] = useDebounceFn<UpdatedCandidatePreferences>(
    (patch) => {
      updatePreferences(patch);
    },
    DEBOUNCE_DELAY_MS,
  );

  useEffect(() => {
    if (!preferences) {
      return;
    }

    if (preferences?.salaryExpectation?.period) {
      setSelectedSalaryOption(
        salaryDurationOptions.findIndex(
          (option) => option.value === preferences.salaryExpectation.period,
        ),
      );
    }
  }, [preferences]);

  return (
    <FlexCol className="gap-6">
      <FlexCol className="gap-2">
        <Typography type={TypographyType.Body} bold>
          What kind of role are you looking for?
        </Typography>

        {/* Role */}
        <Textarea
          inputId="role"
          label="role"
          rows={5}
          maxLength={400}
          placeholder="Describe your next ideal role or career goal…"
          fieldType="quaternary"
          value={preferences?.role}
          onChange={(e) => {
            debouncedUpdate({
              role: e.target.value,
            });
          }}
        />

        {/* Role Type */}
        <Radio
          className={{ container: 'flex-1 !flex-row flex-wrap' }}
          name="role_type"
          options={[
            { label: 'Auto (Recommended)', value: RoleType.Auto.toFixed(1) },
            { label: 'IC roles', value: RoleType.IC.toFixed(1) },
            {
              label: 'Managerial roles',
              value: RoleType.Managerial.toFixed(1),
            },
          ]}
          value={preferences?.roleType?.toFixed(1)}
          onChange={(value) => {
            updatePreferences({ roleType: parseFloat(value) });
          }}
        />
      </FlexCol>

      {/* Employment type */}
      <FlexCol className="gap-2">
        <Typography type={TypographyType.Body} bold>
          Employment type
        </Typography>
        <Typography
          type={TypographyType.Footnote}
          color={TypographyColor.Tertiary}
        >
          Select all that apply to the roles you&apos;d consider.
        </Typography>

        {/* Employment type */}
        <FlexRow className="flex-wrap">
          {employmentTypeOptions.map(({ label, value }) => (
            <Checkbox
              key={value}
              name={value.toString()}
              checked={preferences?.employmentType?.includes(value)}
              onToggleCallback={(checked) => {
                const employmentType = preferences?.employmentType || [];
                updatePreferences({
                  employmentType: checked
                    ? [...employmentType, value]
                    : employmentType.filter((v) => v !== value),
                });
              }}
            >
              {label}
            </Checkbox>
          ))}
        </FlexRow>
      </FlexCol>

      {/* Salary expectations */}
      <FlexCol className="gap-2">
        <Typography type={TypographyType.Body} bold>
          Salary expectations
        </Typography>
        <Typography
          type={TypographyType.Footnote}
          color={TypographyColor.Tertiary}
        >
          Give a minimum so we only surface roles that meet your requirements.
        </Typography>
        <FlexRow className="gap-3">
          <TextField
            inputId="min"
            label="USD"
            value={preferences?.salaryExpectation?.min?.toLocaleString('en-US')}
            className={{ container: 'w-40' }}
            onChange={(e) => {
              const min = parseFloat(e.target.value.replace(/,/g, ''));
              updatePreferences({
                salaryExpectation: {
                  ...preferences.salaryExpectation,
                  period: preferences.salaryExpectation?.period
                    ? preferences.salaryExpectation.period
                    : SalaryPeriod.ANNUAL,
                  min: Number.isNaN(min) ? null : min,
                },
              });
            }}
          />
          <Dropdown
            selectedIndex={selectedSalaryOption}
            options={salaryOptions}
            className={{ label: 'text-text-primary' }}
            onChange={(option) => {
              const index = salaryOptions.indexOf(option);

              updatePreferences({
                salaryExpectation: {
                  ...preferences.salaryExpectation,
                  period: salaryDurationOptions[index].value,
                },
              });
            }}
          />
        </FlexRow>
      </FlexCol>

      {/* Location preferences */}
      <FlexCol className="gap-2">
        <Typography type={TypographyType.Body} bold>
          Location preferences
        </Typography>
        <Typography
          type={TypographyType.Footnote}
          color={TypographyColor.Tertiary}
        >
          Tell us where you want to work from.
        </Typography>
        <FlexRow className="gap-3">
          <TextField
            inputId="country"
            label="Country"
            value={preferences?.location?.[0]?.country}
            className={{ container: 'flex-1' }}
            onChange={(e) => {
              debouncedUpdate({
                location: [
                  {
                    ...preferences?.location?.[0],
                    country: e.target.value,
                  },
                ],
              });
            }}
          />
          <TextField
            inputId="city"
            label="City"
            value={preferences?.location?.[0]?.city}
            className={{ container: 'flex-1' }}
            onChange={(e) => {
              debouncedUpdate({
                location: [
                  {
                    ...preferences?.location?.[0],
                    city: e.target.value,
                  },
                ],
              });
            }}
          />
        </FlexRow>

        {/* Location type */}
        <FlexRow>
          {locationTypeOptions.map(({ label, value }) => (
            <Checkbox
              key={value}
              name={value.toString()}
              checked={preferences?.locationType?.includes(value)}
              onToggleCallback={(checked) => {
                const locationType = preferences?.locationType || [];
                updatePreferences({
                  locationType: checked
                    ? [...locationType, value]
                    : locationType.filter((v) => v !== value),
                });
              }}
            >
              {label}
            </Checkbox>
          ))}
        </FlexRow>
      </FlexCol>

      {/* Tech stack */}
      <FlexCol className="gap-2">
        <Typography type={TypographyType.Body} bold>
          Preferred tech stack
        </Typography>
        <Typography
          type={TypographyType.Footnote}
          color={TypographyColor.Tertiary}
        >
          Define the tools, technologies, and languages you want in your next
          role.
        </Typography>
        <Radio
          className={{ container: '!flex-row flex-wrap' }}
          name="tech_stack"
          options={[
            { label: 'Copy from my profile (Recommended)', value: 'false' },
            { label: 'Select manually', value: 'true' },
          ]}
          value={preferences?.customKeywords ? 'true' : 'false'}
          onChange={(value) => {
            updatePreferences({
              customKeywords: stringToBoolean(value),
            });
          }}
        />

        {preferences?.customKeywords && (
          <KeywordSelection
            keywords={preferences?.keywords}
            addKeyword={addKeyword}
            removeKeyword={removeKeyword}
          />
        )}
      </FlexCol>
    </FlexCol>
  );
};
